/*
Java board game library.
Copyright (C) 2011  Deepesh Garg

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package d.g.boardgames.chess;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import d.g.boardgames.Cell;
import d.g.boardgames.chess.ChessCellState.PieceType;
import d.g.boardgames.chess.ChessMove.Casteling;


public class PGNMoveParser implements ChessMoveParser {

	@Override
	public String createMoveString(ChessBoard board, ChessMove move) {
		if (move.getCasteling() != null) {
			if (move.getCasteling() == Casteling.KING_SIDE) {
				return "O-O";
			}
			if (move.getCasteling() == Casteling.QUEEN_SIDE) {
				return "O-O-O";
			}
		}
		ChessCellState cellState = board.getCellState(move.getFromCell());
		if (cellState == null) {
			return null;
		}
		String moveString = "";
		moveString = AlgebricNotationHelper.getPieceString(cellState.pieceType);
		//Get same piece of same color on other cell (then fromCell)
		// get valid moves for those and if valid move contains toCell 
		// prepend a qualifier to moveString.
		List<Cell> otherCells = new ArrayList<Cell>();
		for (int row = 0; row < board.getRowCount(); row++) {
			for (int col = 0; col < board.getColCount(); col++) {
				Cell thisCell = new Cell(row, col);
				ChessCellState state = board.getCellState(thisCell);
				if (state != null && 
					state.pieceType == cellState.pieceType && state.pieceColor == cellState.pieceColor &&
					!thisCell.equals(move.fromCell)) {
					List<Cell> possibleMoves = ChessMoveHelper.getPossibleMoves(board, thisCell);
					if (possibleMoves.contains(move.toCell)) {
						otherCells.add(thisCell);
					}
				}
			}
		}
		if (otherCells.size() > 0) {
			boolean rankOverlap = false;
			boolean fileOverlap = false;
			for (Cell otherCell: otherCells) {
				if (otherCell.getRow() == move.fromCell.getRow()) {
					rankOverlap = true;
				}
				if (otherCell.getCol() == move.fromCell.getCol()) {
					fileOverlap = true;
				}
			}
			if (rankOverlap || (!rankOverlap && !fileOverlap)) {
				moveString += AlgebricNotationHelper.getFileString(move.fromCell.getCol());
			}
			if (fileOverlap) {
				moveString += AlgebricNotationHelper.getRankString(move.fromCell.getRow());
			}
		}
		if (board.getCellState(move.toCell) != null || move.toCell.equals(board.getPassedPawn())) {
			moveString += "x";
		}
		moveString += AlgebricNotationHelper.getCellString(move.getToCell());
		if (move.getPawnPromotion() != null) {
			moveString+= "=" + AlgebricNotationHelper.getPieceString(move.getPawnPromotion());
		}
		ChessBoard boardAfter = board.move(move);
		if (ChessMoveHelper.kingInCheck(boardAfter, boardAfter.getTurn())) {
			moveString += "+" ;
		}
		return moveString;
	}

	@Override
	public ChessMove parseMoveString(ChessBoard board, String moveString) {
		ChessMove chessMove = new ChessMove();
		//([NBRQKnrqk]?)([abcdefgh]?)([12345678]?)([abcdefgh]{1}[12345678]{1})
		moveString = filterExtraCharacters(moveString);
		if (moveString.equalsIgnoreCase("oo")) {
			return new ChessMove (Casteling.KING_SIDE);
		}
		if (moveString.equalsIgnoreCase("ooo")) {
			return new ChessMove (Casteling.QUEEN_SIDE);
		}
		Pattern pattern = Pattern.compile("([NBRQKnrqk]?)([abcdefgh]?)([12345678]?)([abcdefgh]{1}[12345678]{1})(=[NBRQnrq])?");
		Matcher matcher = pattern.matcher(moveString);
		matcher.find();
		PieceType pieceToMove = AlgebricNotationHelper.getPieceType(matcher.group(1));
		Cell toCell = AlgebricNotationHelper.getCell(matcher.group(4));
		chessMove.setToCell(toCell);
		List<Cell> possibleFromCellList = new ArrayList<Cell>();
		String pawnPromotionStr = matcher.group(5);
		if (pawnPromotionStr != null && !pawnPromotionStr.trim().equals("")) {
			chessMove.pawnPromotion = AlgebricNotationHelper.getPieceType(pawnPromotionStr.substring(pawnPromotionStr.length() - 1, pawnPromotionStr.length())) ;
		}
		for (int row = 0; row < board.getRowCount(); row++) {
			for (int col = 0; col < board.getColCount(); col++) {
				Cell thisCell = new Cell(row, col);
				ChessCellState state = board.getCellState(thisCell);
				if (state != null && 
					state.pieceType == pieceToMove && state.pieceColor == board.turn) {
					List<Cell> possibleMoveList = ChessMoveHelper.getPossibleMoves(board, thisCell);
					if (possibleMoveList.contains(toCell)) {
						possibleFromCellList.add(thisCell);
					}
				}
			}
		}
		if (possibleFromCellList.size() == 1) {
			chessMove.setFromCell(possibleFromCellList.get(0));
			return chessMove;
		}
		int row = -1;
		int col = -1;
		String fileStr = matcher.group(2);
		String rankStr = matcher.group(3);
		if (!fileStr.equals("")) {
			col = AlgebricNotationHelper.getCol(fileStr.charAt(0));
		}
		if (!rankStr.equals("")) {
			row = AlgebricNotationHelper.getRow(rankStr.charAt(0));
		}
		for (Cell possibleFromCell: possibleFromCellList) {
			if ( (row < 0 || possibleFromCell.getRow() == row) &&
			     (col < 0 || possibleFromCell.getCol() == col) ) {
				chessMove.setFromCell(possibleFromCell);
				return chessMove;
			}
		}
		return null;
	}
	
	String filterExtraCharacters (String moveString) {
		String filteredMoveString = "";
		String validCharacters = "abcdefgh12345678pPnNBrRqQkKoO=";
		for (int i = 0; i < moveString.length(); i++) {
			String checkCharacter = moveString.substring(i, i+1);
			if (validCharacters.contains(checkCharacter)) {
				filteredMoveString += checkCharacter;
			}
		}
		return filteredMoveString;
	}
}
